{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = 'all'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.通过重定向/管道/文件接受输入"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/etc/passwd 1 root:x:0:0:root:/root:/bin/bash\n"
     ]
    }
   ],
   "source": [
    "import fileinput\n",
    "with fileinput.input('/etc/passwd') as f:\n",
    "    for line in f:\n",
    "        print(f.filename(), f.lineno(), line, end='')\n",
    "        break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.终止程序并给出错误信息\n",
    "\n",
    "你想向标准错误打印一条消息并返回某个非零状态码来终止程序运行。\n",
    "\n",
    "`raise SystemExit('It failed!')`抛出一个 SystemExit 异常，使用错误消息作为参数。它会将消息在 sys.stderr 中打印，然后程序以状态码1退出。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "SystemExit",
     "evalue": "It failed!",
     "output_type": "error",
     "traceback": [
      "An exception has occurred, use %tb to see the full traceback.\n",
      "\u001b[0;31mSystemExit\u001b[0m\u001b[0;31m:\u001b[0m It failed!\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/ubuntu/anaconda3/lib/python3.9/site-packages/IPython/core/interactiveshell.py:3452: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n",
      "  warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n"
     ]
    }
   ],
   "source": [
    "raise SystemExit('It failed!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.解析命令行选项"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# search.py\n",
    "import argparse\n",
    "parser = argparse.ArgumentParser(description='Search some files')\n",
    "\n",
    "parser.add_argument(dest='filenames',metavar='filename', nargs='*')\n",
    "\n",
    "parser.add_argument('-p', '--pat',metavar='pattern', required=True,\n",
    "                    dest='patterns', action='append',\n",
    "                    help='text pattern to search for')\n",
    "\n",
    "parser.add_argument('-v', dest='verbose', action='store_true',\n",
    "                    help='verbose mode')\n",
    "\n",
    "parser.add_argument('-o', dest='outfile', action='store',\n",
    "                    help='output file')\n",
    "\n",
    "parser.add_argument('--speed', dest='speed', action='store',\n",
    "                    choices={'slow','fast'}, default='slow',\n",
    "                    help='search speed')\n",
    "\n",
    "args = parser.parse_args()\n",
    "\n",
    "# Output the collected arguments\n",
    "print(args.filenames)\n",
    "print(args.patterns)\n",
    "print(args.verbose)\n",
    "print(args.outfile)\n",
    "print(args.speed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.运行时弹出密码输入提示\n",
    "\n",
    "Python的 getpass 模块正是你所需要的。你可以让你很轻松的弹出密码输入提示， 并且不会在用户终端回显密码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import getpass\n",
    "\n",
    "# getpass.getuser() 不会弹出用户名的输入提示\n",
    "user = getpass.getuser()\n",
    "\n",
    "# 如果你想显示的弹出用户名输入提示，使用内置的 input 函数\n",
    "user = input('Enter your username: ')\n",
    "\n",
    "# 获取密码\n",
    "passwd = getpass.getpass()\n",
    "\n",
    "# You must write svc_login()\n",
    "# svc_login() 是你要实现的处理密码的函数，具体的处理过程自己决定\n",
    "if svc_login(user, passwd):    \n",
    "   print('Yay!')\n",
    "else:\n",
    "   print('Boo!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.获取终端的大小\n",
    "\n",
    "```python\n",
    ">>> import os\n",
    ">>> sz = os.get_terminal_size()\n",
    ">>> sz\n",
    "os.terminal_size(columns=80, lines=24)\n",
    ">>> sz.columns\n",
    "80\n",
    ">>> sz.lines\n",
    "24\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.执行外部命令并获取它的输出\n",
    "\n",
    "执行一个外部命令并以Python字符串的形式获取执行结果， 可以使用 subprocess.check_output() 函数。\n",
    "\n",
    "```python\n",
    "\n",
    "import subprocess\n",
    "out_bytes = subprocess.check_output(['netstat','-a'])\n",
    "out_text = out_bytes.decode('utf-8')\n",
    "\n",
    "```\n",
    "\n",
    "```python\n",
    "\n",
    "try:\n",
    "    out_bytes = subprocess.check_output(['cmd','arg1','arg2'])\n",
    "except subprocess.CalledProcessError as e:\n",
    "    out_bytes = e.output       # Output generated before error\n",
    "    code      = e.returncode   # Return code\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7.复制或者移动文件和目录\n",
    "\n",
    "shutil 模块有很多便捷的函数可以复制文件和目录。\n",
    "\n",
    "```python\n",
    "import shutil\n",
    "\n",
    "# Copy src to dst. (cp src dst)\n",
    "shutil.copy(src, dst)\n",
    "\n",
    "# Copy files, but preserve metadata (cp -p src dst)\n",
    "shutil.copy2(src, dst)\n",
    "\n",
    "# Copy directory tree (cp -R src dst)\n",
    "shutil.copytree(src, dst)\n",
    "\n",
    "# Move src to dst (mv src dst)\n",
    "shutil.move(src, dst)\n",
    "\n",
    "\n",
    "def ignore_pyc_files(dirname, filenames):\n",
    "    return [name in filenames if name.endswith('.pyc')]\n",
    "shutil.copytree(src, dst, ignore=ignore_pyc_files)\n",
    "\n",
    "\n",
    "shutil.copytree(src, dst, ignore=shutil.ignore_patterns('*~', '*.pyc'))\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8.创建和解压归档文件\n",
    "\n",
    "shutil 模块拥有两个函数—— make_archive() 和 unpack_archive() 可派上用场。\n",
    "\n",
    "```\n",
    "\n",
    ">>> import shutil\n",
    "\n",
    ">>> shutil.get_archive_formats()\n",
    "[('bztar', \"bzip2'ed tar-file\"), ('gztar', \"gzip'ed tar-file\"),\n",
    " ('tar', 'uncompressed tar file'), ('zip', 'ZIP file')]\n",
    ">>>\n",
    "\n",
    ">>> shutil.unpack_archive('Python-3.3.0.tgz')\n",
    "\n",
    ">>> shutil.make_archive('py33','zip','Python-3.3.0')\n",
    "'/Users/beazley/Downloads/py33.zip'\n",
    ">>>\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.通过文件名查找文件\n",
    "\n",
    "查找文件，可使用 os.walk() 函数，传一个顶级目录名给它。 \n",
    "\n",
    "os.walk() 方法为我们遍历目录树， 每次进入一个目录，它会返回一个三元组，包含相对于查找目录的相对路径，一个该目录下的目录名列表， 以及那个目录下面的文件名列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/tmp/pred.xml\n",
      "/tmp/pred.xml\n",
      "/tmp/pred.xml\n"
     ]
    }
   ],
   "source": [
    "# 查找特定的文件名并答应所有符合条件的文件全路径\n",
    "\n",
    "#!/usr/bin/env python3.3\n",
    "import os\n",
    "import sys\n",
    "\n",
    "def findfile(start, name):\n",
    "    for relpath, dirs, files in os.walk(start):\n",
    "        if name in files:\n",
    "            full_path = os.path.join(start, relpath, name)\n",
    "            print(full_path)\n",
    "            print(os.path.abspath(full_path))\n",
    "            print(os.path.normpath(os.path.abspath(full_path)))\n",
    "\n",
    "\n",
    "findfile('/tmp', 'pred.xml')\n",
    "\n",
    "# if __name__ == '__main__':\n",
    "#     findfile(sys.argv[1], sys.argv[2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 10.读取配置文件\n",
    "\n",
    "读取普通.ini格式的配置文件，configparser 模块能被用来读取配置文件。\n",
    "\n",
    "```\n",
    ">>> from configparser import ConfigParser\n",
    ">>> cfg = ConfigParser()\n",
    ">>> cfg.read('config.ini')\n",
    "['config.ini']\n",
    ">>> cfg.sections()\n",
    "['installation', 'debug', 'server']\n",
    ">>> cfg.get('installation','library')\n",
    "'/usr/local/lib'\n",
    ">>> cfg.getboolean('debug','log_errors')\n",
    "\n",
    "True\n",
    ">>> cfg.getint('server','port')\n",
    "8080\n",
    ">>> cfg.getint('server','nworkers')\n",
    "32\n",
    ">>> print(cfg.get('server','signature'))\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 11.给简单脚本增加日志功能\n",
    "\n",
    "打印日志最简单方式是使用 logging 模块。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "\n",
    "def main():\n",
    "    logging.basicConfig(\n",
    "        filename='app.log',\n",
    "        level=logging.WARNING\n",
    "    )\n",
    "\n",
    "     # Variables (to make the calls that follow work)\n",
    "    hostname = 'www.python.org'\n",
    "    item = 'spam'\n",
    "    filename = 'data.csv'\n",
    "    mode = 'r'\n",
    "\n",
    "    logging.critical('Host %s unknown', hostname)\n",
    "    logging.error(\"Couldn't find %r\", item)\n",
    "    logging.warning('Feature is deprecated')\n",
    "    logging.info('Opening file %r, mode=%r', filename, mode)\n",
    "    logging.debug('Got here')\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 12.给函数库增加日志功能\n",
    "\n",
    "给某个函数库增加日志功能，但是又不能影响到那些不使用日志功能的程序。\n",
    "\n",
    "对于想要执行日志操作的函数库而已，应该创建一个专属的 logger 对象，并且像下面这样初始化配置：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__main__\n"
     ]
    }
   ],
   "source": [
    "# somelib.py\n",
    "\n",
    "import logging\n",
    "\n",
    "print(__name__)\n",
    "log = logging.getLogger(__name__)\n",
    "log.addHandler(logging.NullHandler())\n",
    "\n",
    "# Example function (for testing)\n",
    "def func():\n",
    "    log.critical('A Critical Error!')\n",
    "    log.debug('A debug message')\n",
    "\n",
    "# 不会打印日志\n",
    "func()\n",
    "\n",
    "# 配置过日志系统\n",
    "logging.basicConfig()\n",
    "func()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 13.实现一个计时器\n",
    "\n",
    "time 模块包含很多函数来执行跟时间有关的函数。 尽管如此，通常我们会在此基础之上构造一个更高级的接口来模拟一个计时器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.04864522209390998\n",
      "0.09500286215916276\n",
      "0.04786683712154627\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "\n",
    "class Timer:\n",
    "    def __init__(self, func=time.perf_counter):\n",
    "        self.elapsed = 0.0\n",
    "        self._func = func\n",
    "        self._start = None\n",
    "\n",
    "    def start(self):\n",
    "        if self._start is not None:\n",
    "            raise RuntimeError('Already started')\n",
    "        self._start = self._func()\n",
    "\n",
    "    def stop(self):\n",
    "        if self._start is None:\n",
    "            raise RuntimeError('Not started')\n",
    "        end = self._func()\n",
    "        self.elapsed += end - self._start\n",
    "        self._start = None\n",
    "\n",
    "    def reset(self):\n",
    "        self.elapsed = 0.0\n",
    "\n",
    "    @property\n",
    "    def running(self):\n",
    "        return self._start is not None\n",
    "\n",
    "    def __enter__(self):\n",
    "        self.start()\n",
    "        return self\n",
    "\n",
    "    def __exit__(self, *args):\n",
    "        self.stop()\n",
    "\n",
    "\n",
    "def countdown(n):\n",
    "    while n > 0:\n",
    "        n -= 1\n",
    "\n",
    "t = Timer()\n",
    "t.start()\n",
    "countdown(1000000)\n",
    "t.stop()\n",
    "print(t.elapsed)\n",
    "\n",
    "with t:\n",
    "    countdown(1000000)\n",
    "print(t.elapsed)\n",
    "\n",
    "with Timer() as t2:\n",
    "    countdown(1000000)\n",
    "print(t2.elapsed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 14.限制内存和CPU的使用量\n",
    "\n",
    "你想对在Unix系统上面运行的程序设置内存或CPU的使用限制。\n",
    "\n",
    "resource 模块能同时执行这两个任务。\n",
    "\n",
    "需要注意的是本节内容只能适用于Unix系统，并且不保证所有系统都能如期工作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time's up!\n"
     ]
    },
    {
     "ename": "SystemExit",
     "evalue": "1",
     "output_type": "error",
     "traceback": [
      "An exception has occurred, use %tb to see the full traceback.\n",
      "\u001b[0;31mSystemExit\u001b[0m\u001b[0;31m:\u001b[0m 1\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/ubuntu/anaconda3/lib/python3.9/site-packages/IPython/core/interactiveshell.py:3452: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n",
      "  warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n"
     ]
    }
   ],
   "source": [
    "import signal\n",
    "import resource\n",
    "import os\n",
    "\n",
    "def time_exceeded(signo, frame):\n",
    "    print(\"Time's up!\")\n",
    "    raise SystemExit(1)\n",
    "\n",
    "def set_max_runtime(seconds):\n",
    "    # Install the signal handler and set a resource limit\n",
    "    soft, hard = resource.getrlimit(resource.RLIMIT_CPU)\n",
    "    resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard))\n",
    "    signal.signal(signal.SIGXCPU, time_exceeded)\n",
    "\n",
    "def limit_memory(maxsize):\n",
    "    soft, hard = resource.getrlimit(resource.RLIMIT_AS)\n",
    "    resource.setrlimit(resource.RLIMIT_AS, (maxsize, hard))\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    set_max_runtime(15)\n",
    "    while True:\n",
    "        pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 15.启动一个WEB浏览器\n",
    "\n",
    "webbrowser 模块能被用来启动一个浏览器，并且与平台无关。\n",
    "\n",
    "```\n",
    ">>> import webbrowser\n",
    ">>> webbrowser.open('http://www.python.org')\n",
    "True\n",
    ">>>\n",
    ">>> # Open the page in a new browser window\n",
    ">>> webbrowser.open_new('http://www.python.org')\n",
    "True\n",
    ">>>\n",
    ">>> # Open the page in a new browser tab\n",
    ">>> webbrowser.open_new_tab('http://www.python.org')\n",
    "True\n",
    ">>>\n",
    "\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "vscode": {
   "interpreter": {
    "hash": "caf1c2fcf97217de91eafa76b907d50f9ea378f5ffbee7f571142d119bb6a771"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
